#coding=utf-8
# Copyright 2011 Andrey Stepashov <Andrey.Stepashov@gmail.com>
# Copyright 2012 Maxim Petrov <maximpetrov@yahoo.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 3 or any later version.

from panel import Panel
from controls import Pad
from controls import Control
import os
import curses
from filetree_filter_window import FiletreeFilterWindow

class tree_elements_sort_key(object):
    """
    Класс-ключ для сортировки элементов дерева
    """

    def cmp_tree_elements(self, other):
        """
        Функция для сравнения двух элементов дерева файлов. Используется для
        сортировки отображаемых файлов. Файлы сравниваются по именам как обычные
        строки, но каталог всегда меньше файла.

        Аргументы:
            other - элемент дерева для сравнения

        Возвращаемое значение:
            -1 - self.obj <  other.obj,
             0 - self.obj == other.obj,
             1 - self.obj >  other.obj.
        """

        x = self.obj
        y = other.obj
        # x - файл, y - каталог
        if x[1][0] is None and y[1][0] is not None:
            return 1
        # x - каталог, y - файл
        if x[1][0] is not None and y[1][0] is None:
            return -1
        # x и y - либо оба файлы, либо оба каталоги
        return cmp(x[0], y[0])

    def __init__(self, obj, *args):
        self.obj = obj
    def __lt__(self, other):
        return self.cmp_tree_elements(other) < 0
    def __gt__(self, other):
        return self.cmp_tree_elements(other) > 0
    def __eq__(self, other):
        return self.cmp_tree_elements(other) == 0
    def __le__(self, other):
        return self.cmp_tree_elements(other) <= 0
    def __ge__(self, other):
        return self.cmp_tree_elements(other) >= 0
    def __ne__(self, other):
        return self.cmp_tree_elements(other) != 0

def sorted_iter(d):
    """
    Функция для получения итератора отсортированного списка, полученного из
    переданного словаря.

    Аргументы:
    d - словарь

    Возвращаемое значение:
    возвращает итератор отсортированного списка d.items()
    """

    return iter(sorted(d.items(), key = tree_elements_sort_key))

class ListTree(object):
    """
    Класс работы со списком дерева каталогов
    """

    def __init__(self):
        """
        Конструктор
        """

        # Размеры списка. Размер height может не соответствовать длине
        # списка, так как некоторые файлы/директории находятся в
        # закрытых директориях. Размер width равен смещение + длина файла
        self.__width = 0
        self.__height = 0
        # Выделенный файл/директория (разбитый путь от корня: (имя, лист))
        self.__sel_pos = []
        # Дерево файлов/директорий. Формат "листа дерева":
        # имя: [содержимое каталога, статус, флаг выделения, флаг отображения,
        #                                      флаг пустоты, флаг сворачивания]
        # имя - только самого файла/каталога без каталогов верхнего уровня
        # содержимое каталога - словарь таких же "листьев", если этот элемент
        #                       является файлом, то он равен None
        # флаг отображения - для файлов - относится к скрытости из-за фильтров,
        #                    для каталогов - к раскрытости
        # флаг пустоты - для каталогов означает, что все файлы внутри скрыты
        #                фильтром, для файлов - False (ничего не значит)
        # флаг сворачивания - для каталогов означает, что внутри из отображаемых
        #                     элементов находится только один каталог и название
        #                     можно сворачивать в одну строку,
        #                     для файлов - False (ничего не значит)
        self.__filetree = {}

    def set_files(self, files):
        """
        Функция сохраняет список файлов в дерево.

        Аргументы:
        files - список файлов (пути относительно корня) и их статусов.
        """

        self.__filetree.clear()
        for f, st in files:
            # Разбиваем путь к каждому файлу на каталоги и переходим от корня
            # к каталогу, в котором находится файл
            path = f.split(unicode(os.sep))
            cur_dir = self.__filetree
            for d in path[:-1]:
                if cur_dir.has_key(d):
                    cur_dir = cur_dir[d][0]
                else:
                    subdir = {}
                    cur_dir.update({d: [subdir, u' ', False, True, False, False]})
                    cur_dir = subdir
            # Добавляем файл в каталог
            cur_dir.update({path[-1]: [None, st, False, True, False, False]})
        self.__set_size()
        self.set_pos(u"HOME")

    def get_filelist(self):
        """
        Функция возвращает список файлов, которые
        имеют статус отображать

        Возвращаемое значение:
        filelist - список файлов
        """
        filelist = []
        # Обходим дерево файлов не заходя в свернутые каталоги и не добавляя
        # скрытые файлы.
        tree_stack = [sorted_iter(self.__filetree)]
        while len(tree_stack) > 0:
            if len(tree_stack) == 1:
                cur_folding = u''
                cur_fold_unshift = 0
            try:
                name, value = tree_stack[-1].next()
            except StopIteration:
                tree_stack.pop()
            else:
                subdir, st, sel, vis, empty, fold = value
                if not empty:
                    if subdir is not None:
                        name = unicode(os.sep) + name
                    if subdir is not None or vis:
                        if fold:
                            cur_folding += name
                            cur_fold_unshift += 1
                        else:
                            filelist.append((len(tree_stack) - 1 - cur_fold_unshift,
                                                cur_folding + name, sel, st))
                            cur_folding = u''
                    if (subdir is not None and vis) or fold:
                        tree_stack.append(sorted_iter(subdir))
        return filelist

    def get_curpath(self, ignore_dirs=True):
        """
        Функция возвращает текущий путь
        Аргументы:
        ignore_dirs (по умолчанию - True) - если установлен в True, то для
        директорий возвращается пустая строка
        Возвращаемое значение:
        curpath - текущий путь
        """
        if len(self.__filetree) == 0:
            return
        appendix = u""
        if self.__sel_pos[-1][1][0] is not None:
            if ignore_dirs:
                return
            else:
                appendix = u"/"
        return unicode(os.sep).join([d[0] for d in self.__sel_pos]) + appendix

    def get_size(self):
        """
        Функция возвращает количество строк и смещение + имя
        самого длинного названия

        Возвращаемое значение:
        (height, width) - высота и длина
        """
        height = self.__height
        width = self.__width
        return (height, width)

    def get_selected_files(self):
        """
        Функция возвращает список путей к выделенным файлам

        Возвращаемое значение:
        s_list - список файлов
        """

        s_list = []
        # Обходим дерево файлов
        tree_stack = [(u'', sorted_iter(self.__filetree))]
        while len(tree_stack) > 0:
            try:
                name, value = tree_stack[-1][1].next()
            except StopIteration:
                tree_stack.pop()
            else:
                subdir, st, sel, vis, empty, fold = value
                if subdir is not None and not empty:
                    tree_stack.append((name, sorted_iter(subdir)))
                if subdir is None and sel:
                    full_name = u'/'.join([d[0] for d in tree_stack[1:]] + [name])
                    s_list.append(full_name)
        return s_list

    def set_selected(self):
        """
        Функция устанавливает выделение
        """
        self.__sel_pos[-1][1][2] = not self.__sel_pos[-1][1][2]
        if self.__sel_pos[-1][1][0] is not None:
            # Обходим поддерево для выбранного каталога и выделяем все файлы
            sel_st = self.__sel_pos[-1][1][2]
            tree_stack = [sorted_iter(self.__sel_pos[-1][1][0])]
            while len(tree_stack) > 0:
                try:
                    value = tree_stack[-1].next()[1]
                except StopIteration:
                    tree_stack.pop()
                else:
                    subdir, st, sel, vis, empty, fold = value
                    value[2] = sel_st and (vis or subdir is not None) and not empty
                    if subdir is not None and not empty:
                        tree_stack.append(sorted_iter(subdir))

    def set_deselected(self):
        """
        Функция снимает все выделения
        """
        # Обходим дерево файлов, снимая выделение со всех файлов
        tree_stack = [sorted_iter(self.__filetree)]
        while len(tree_stack) > 0:
            try:
                value = tree_stack[-1].next()[1]
            except StopIteration:
                tree_stack.pop()
            else:
                value[2] = False
                if value[0] is not None:
                    tree_stack.append(sorted_iter(value[0]))

    def set_file_filter(self, st_filter):
        """
        Функция скрывает файлы со статусами не из st_filter
        Если выделенный файл скрывается, с него снимается выделение

        Аргументы:
            st_filter - список показываемых статусов
        """

        # Показываем файлы с пустым статусом (файлы с неопределенным статусом,
        # пока это файлы из панели конфликтов)
        st_filter = st_filter + [u' '];
        # Обходим дерево файлов
        # Первый элемент в тройке в стеке - количество элементов в каталоге
        # для определения пустых каталогов, второй - каталог, чей итератор
        # в третьем элементе
        tree_stack = [[0, None, sorted_iter(self.__filetree)]]
        while len(tree_stack) > 0:
            try:
                value = tree_stack[-1][2].next()[1]
            except StopIteration:
                size, elem, it = tree_stack.pop()
                if len(tree_stack) > 0:
                    if size > 0:
                        elem[4] = False
                    else:
                        tree_stack[-1][0] -= 1
                        elem[4] = True
                    if size != 1:
                        elem[5] = False
            else:
                if value[0] is None:
                    if st_filter.count(value[1]) == 0:
                        value[3] = False
                        value[2] = False
                    else:
                        value[3] = True
                        tree_stack[-1][0] += 1
                        if tree_stack[-1][1] is not None:
                            tree_stack[-1][1][5] = False
                if value[0] is not None:
                    tree_stack[-1][0] += 1
                    value[5] = True
                    tree_stack.append([0, value, sorted_iter(value[0])])
        # Повторно проходим по дереву, чтобы устранить разрывы в признаке
        # сворачивания, так как до этого учитывалось только содержимое каталогов,
        # но возможно. что к текущему каталогу уже разорвалась цепоцка сворачиваний
        tree_stack = [[sorted_iter(self.__filetree), True]]
        while len(tree_stack) > 0:
            try:
                should_fold = tree_stack[-1][1]
                value = tree_stack[-1][0].next()[1]
            except StopIteration:
                tree_stack.pop()
            else:
                value[5] = should_fold = should_fold and value[5]
                value[2] = False
                if value[0] is not None:
                    tree_stack.append([sorted_iter(value[0]), should_fold])
        self.__set_size()
        self.set_pos(u"HOME")

    def change_dir_state(self):
        """
        Функция открытия/закрытия директории. Открытую директорию закрывает,
        закрытую - открывает.
        """
        if self.__sel_pos[-1][1][0] is not None:
            self.__sel_pos[-1][1][3] = not self.__sel_pos[-1][1][3]
        self.__set_size()

    def __set_size(self):
        """
        Функция устанавливает __width и __height
        """
        self.__height = 0
        self.__width = 0
        # Обходим дерево файлов и считаем количество отображаемых файлов и
        # максимальную длину их имени
        tree_stack = [sorted_iter(self.__filetree)]
        while len(tree_stack) > 0:
            if len(tree_stack) == 1:
                cur_folding_len = 0
            try:
                name, value = tree_stack[-1].next()
            except StopIteration:
                tree_stack.pop()
            else:
                subdir, st, sel, vis, empty, fold = value
                if ((subdir is not None and vis) or fold) and not empty:
                    tree_stack.append(sorted_iter(subdir))
                if fold:
                    cur_folding_len += len(name)
                if not empty and (subdir is not None or vis) and not fold:
                    self.__height += 1
                    self.__width = max(self.__width,
                            len(tree_stack) - 1 + len(name) + cur_folding_len)
                    cur_folding_len = 0

    def set_pos(self, action):
        """
        Функция устанавливает выделенную позицию в __filetree

        Аргументы:
        action - действие: UP, DOWN, HOME, END

        Возвращаемое значение:
        True - позиция установлена
        False - неправильный аргумент или __filetree пуст
        """
        if self.__height == 0:
            return False
        if action == u"UP":
            while True:
                name = self.__sel_pos.pop()[0]
                if len(self.__sel_pos) > 0:
                    cur_dir = self.__sel_pos[-1][1][0]
                else:
                    cur_dir = self.__filetree
                items = cur_dir.items()
                items.sort(key = tree_elements_sort_key)
                keys = zip(*items)[0]
                i = keys.index(name) - 1
                while i >= 0:
                    value = items[i][1]
                    if not value[4]:
                        if value[0] is not None:
                            self.__sel_pos.append(items[i])
                            if value[3] or value[5]:
                                self.__sel_pos += self.__get_last_visible(value[0])
                            break
                        elif value[3]:
                            self.__sel_pos.append(items[i])
                            break
                    i -= 1
                if len(self.__sel_pos) == 0 or not self.__sel_pos[-1][1][5]:
                    break
            if len(self.__sel_pos) == 0:
                cur_dir = self.__filetree
                while True:
                    for name, value in sorted(cur_dir.items(),
                                              key = tree_elements_sort_key):
                        if not value[4] and (value[0] is not None or value[3]):
                            self.__sel_pos += [(name, value)]
                            cur_dir = value[0]
                            break
                    if not self.__sel_pos[-1][1][5]:
                        break
        elif action == u"DOWN":
            pos_backup = []
            pos_backup.extend(self.__sel_pos)
            while True:
                value = self.__sel_pos[-1][1]
                if not value[4] and value[0] is not None and (value[3] or value[5]):
                    for n, v in sorted(value[0].items(), key = tree_elements_sort_key):
                        if not v[4] and (v[0] is not None or v[3]):
                            self.__sel_pos += [(n, v)]
                            break
                else:
                    while len(self.__sel_pos) > 0:
                        name = self.__sel_pos.pop()[0]
                        if len(self.__sel_pos) > 0:
                            cur_dir = self.__sel_pos[-1][1][0]
                        else:
                            cur_dir = self.__filetree
                        items = cur_dir.items()
                        items.sort(key = tree_elements_sort_key)
                        keys = zip(*items)[0]
                        i = keys.index(name) + 1
                        while i < len(keys):
                            value = items[i][1]
                            if not value[4] and (value[0] is not None or value[3]):
                                self.__sel_pos.append(items[i])
                                break
                            i += 1
                        else:
                            continue
                        break
                if len(self.__sel_pos) == 0 or not self.__sel_pos[-1][1][5]:
                    break
            if len(self.__sel_pos) == 0:
                self.__sel_pos = pos_backup
        elif action == u"HOME":
            cur_dir = self.__filetree
            self.__sel_pos = []
            while True:
                for name, value in sorted(cur_dir.items(),
                                          key = tree_elements_sort_key):
                    if not value[4] and (value[0] is not None or value[3]):
                        self.__sel_pos += [(name, value)]
                        cur_dir = value[0]
                        break
                if not self.__sel_pos[-1][1][5]:
                    break
        elif action == u"END":
            self.__sel_pos = self.__get_last_visible(self.__filetree)
        else:
            return False
        return True

    def __get_last_visible(self, subdir):
        """
        Функция получает путь до последнего видимого элемента в поддереве

        Аргументы:
        subdir - корневой каталог для поиска (словарь)

        Возвращаемое значение:
        возвращает список пар (имя, лист) описывающих путь от subdir
        до последнего видимого файла.
        """

        pos = []
        cur_dir = subdir
        i = len(subdir)
        while i > 0:
            i -= 1
            items = cur_dir.items()
            items.sort(key = tree_elements_sort_key)
            name = items[i][0]
            value = items[i][1]
            if not value[4]:
                if value[0] is not None or value[3]:
                    pos.append(items[i])
                if (value[0] is None and value[3]) or \
                    (value[0] is not None and not value[3] and not value[5]):
                    break
                if value[0] is not None:
                    cur_dir = value[0]
                    i = len(value[0])
        return pos

class FileTreePanel(Panel):
    """
    Класс работы с панелью дерева файлов
    """

    _window = None
    # Текущая ширина окна
    __width = 0
    # Текущая высота окна
    __height = 0
    # Текущее положение окна по х
    __x = 0
    # Текущее положение окна по y
    __y = 0
    # Текущая ширина pad
    __p_width = 0;
    # Текущая высота pad
    __p_height = 0;
    # Параметры фильтра
    __filter_list = []
    # Строки и их атрибуты, передаваемые в ПАД
    __line_and_attr = []

    def __init__(self, main_win):
        """
        Конструктор класса.
        """

        # Дерево каталогов
        self.__list_tree = ListTree()
        # Выделенный файл/директория
        self.__sel_pos = 0
        # Позиция окна относительно pad
        self.__x_pos = 0
        self.__y_pos = 0
        # Список отображаемых файлов/директорий
        self.__filelist = []
        # Скрываем игнорируемые и неизмененные файлы
        self.__filter_list = main_win.settings.get(type(self).__name__, u'filter')
        if self.__filter_list is None:
            self.__filter_list = [u'M', u'A', u'R', u'!', u'?']
        self._window = main_win
        self.__p_width = 1
        self.__p_height = 0

        self.__pad = Pad(self._window,
                         lambda w, h: (1, 1, w - 2, h - 2),
                         lambda s, c: ((f)
                                  for f in self.__line_and_attr[s:s+c]))
        self.__pad.x_shift = 0;
        self.__pad.y_shift = 0;

    def __upd(self):
        """
        Функция отрисовки
        """

        if not self.visible:
            return
        self.__sw.erase()
        self.__sw.box()
        if (self.__height > 1) and (self.__width > 6):
            self.__sw.addstr(0, 5, self._window.str_to_external(self._title()[:self.__width - 6]))

        if self.__height > 2 and self.__width > 2:
            self.__pad.draw(self.__x, self.__y, self.__width, self.__height)
        self.__sw.refresh()

    def __upd_pad(self):
        """
        Функция заполнения pad
        """
        size = 0
        self.__p_height, size = self.__list_tree.get_size()
        size += 8
        if size < self.__width:
            size = self.__width - 2
        if self.__p_height == 0:
            self.__p_height = 1
        self.__p_width = size
        y = 0
        self.__line_and_attr = []
        self.__pad.x_shift = self.__x_pos
        self.__pad.y_shift = self.__y_pos
        for count, name, is_sel, st in self.__filelist:
            str_tmp = u"[" + st + u"] " + count * u" " + u"|-" + name
            attr = self.__get_attr(st)
            if is_sel:
                attr = self._window.color_scheme.selected|curses.A_BOLD
                self.__line_and_attr.append( (str_tmp[self.__x_pos:], None, \
                              [(self.__x_pos, self.__x_pos + self.__width, attr)]) )
            else:
                self.__line_and_attr.append( (str_tmp[self.__x_pos:], None, \
                              [(self.__x_pos, self.__x_pos + self.__width, attr)]) )
            y += 1

    def __get_attr(self, st):
        attr = curses.A_NORMAL
        if st == u'M':
            attr = self._window.color_scheme.modified
        if st == u'?':
            attr = self._window.color_scheme.unknown
        if st == u'I':
            attr = self._window.color_scheme.ignored
        if st == u'A':
            attr = self._window.color_scheme.added
        return attr

    def __is_file(self, y):
        """
        Функция определения файл это или директория

        Аргументы:
        y - номер объекта в __filelist

        Возвращаемое значение:
        True - если это файл
        False - если это директория
        """
        if self.__filelist[y][1][0] != unicode(os.sep):
            return True
        return False

    def __is_dir(self):
        """
        Функция определения директория это или файл. Если директория, то
        обнавляются смещение и текущая директория

        Возвращаемое значение:
        True - если это директория
        False - если это файл
        """
        if self.__is_file(self.__sel_pos):
            return False
        else:
            self.__list_tree.change_dir_state()
            self.__filelist = self.__list_tree.get_filelist()
            return True

    def __select(self, old_sel_pos, old_x_pos):
        """
        Функция снятия выделения с одной строки и установка на другую строку

        Аргументы:
        old_sel_pos - старое положение по y
        old_x_pos - старое положение по x
        """
        if len(self.__filelist) > 0:
            if len(self.__filelist) > old_sel_pos:
                st = self.__filelist[old_sel_pos][3]
                attr_old = self.__get_attr(st)
                if self.__filelist[old_sel_pos][2] == False:
                    str_tmp, tmp, attr_tmp = self.__line_and_attr[old_sel_pos]
                    self.__line_and_attr[old_sel_pos] = (str_tmp, None, \
                            [(old_x_pos, self.__p_width, attr_old)])
                else:
                    str_tmp, tmp, attr_tmp = self.__line_and_attr[old_sel_pos]
                    self.__line_and_attr[old_sel_pos] = (str_tmp, None, \
                           [(old_x_pos, self.__p_width, self._window.color_scheme.selected | \
                                                                        curses.A_BOLD)])
            st = self.__filelist[self.__sel_pos][3]
            attr = self.__get_attr(st)
            if self.__filelist[self.__sel_pos][2] == False:
                str_tmp, tmp, attr_tmp = self.__line_and_attr[self.__sel_pos]
                self.__line_and_attr[self.__sel_pos] = (str_tmp, None,\
                        [(self.__x_pos, self.__x_pos + self.__width, \
                         curses.color_pair(curses.pair_number(attr)+1) | curses.A_REVERSE)])
            else:
                str_tmp, tmp, attr_tmp = self.__line_and_attr[self.__sel_pos]
                self.__line_and_attr[self.__sel_pos] = (str_tmp, None,\
                        [(self.__x_pos, self.__x_pos + self.__width, \
                     self._window.color_scheme.selected_inv | curses.A_REVERSE|curses.A_BOLD)])

    def redraw(self, sw, content_only=False):
        """
        Функция перемещения и изменения размера

        Аргументы:
        sw - новый объект subwin
        content_only - только перезагрузить отображаемое содержимое,
                       не отрисовывая его
        """
        self.__pad.window = sw
        self.__y, self.__x = sw.getbegyx()
        self.__height, self.__width = sw.getmaxyx()
        self.__sw = sw
        self.__upd_pad()
        if not content_only:
            self.__upd()

    def handle_keypress(self, ch, uni):
        """
        Обработчик нажатия клавиши

        Аргументы:
        ch - нажатая клавиша
        uni - True, если ch - является символом Unicode, False - если нет (например,
        является кодом клавиши не являющейся буквой)
        """
        old_sel_pos = self.__sel_pos
        old_x_pos = self.__x_pos
        if ch == curses.KEY_END:
            self.__key_end()
        elif ch == curses.KEY_HOME:
            self.__key_home()
        elif ch == curses.KEY_UP:
            self.__key_up()
        elif ch == curses.KEY_DOWN:
            self.__key_down()
        elif ch == curses.KEY_LEFT:
            if self.__x_pos > 0:
                self.__x_pos -= 1
        elif ch == curses.KEY_RIGHT:
            if self.__x_pos < self.__p_width - self.__width + 2:
                self.__x_pos += 1
        elif ch == ord('\n'):
            if len(self.__filelist) > 0 and self.__is_dir():
                self.__upd_pad()
        elif ch == curses.KEY_IC:
            if len(self.__filelist) > 0:
                self.__list_tree.set_selected()
                self.__filelist = self.__list_tree.get_filelist()
                if self.__sel_pos < self.__p_height - 1:
                    self.__key_down()
        elif ch == curses.KEY_F7:
            self.__list_tree.set_deselected()
            self.__filelist = self.__list_tree.get_filelist()
        elif ch == curses.KEY_F4:
            self.set_filter()
        elif ch == curses.KEY_F6:
            self.__filter_list = [u'M', u'A', u'R', u'!', u'?']
            self._window.settings.set(type(self).__name__, u'filter', self.__filter_list)
            self.__list_tree.set_file_filter(self.__filter_list)
            self.__filelist = self.__list_tree.get_filelist()
            self.__key_home()
        else:
            return
        self.__upd_pad()
        self.__select(old_sel_pos, old_x_pos)
        self.__upd()

    def __key_down(self):
        if self.__sel_pos < self.__p_height - 1:
            self.__sel_pos += 1
        if self.__sel_pos - self.__y_pos > self.__height - 3:
            self.__y_pos += 1
        self.__list_tree.set_pos(u"DOWN")

    def __key_up(self):
        if self.__sel_pos > 0:
            self.__sel_pos -= 1
        if self.__sel_pos - self.__y_pos < 0:
            self.__y_pos -= 1
        self.__list_tree.set_pos(u"UP")

    def __key_end(self):
        self.__sel_pos = self.__p_height - 1
        self.__y_pos = self.__p_height - self.__height + 2
        if self.__y_pos < 0:
            self.__y_pos = 0
        self.__list_tree.set_pos(u"END")

    def __key_home(self):
        self.__y_pos = 0
        self.__sel_pos = 0
        self.__list_tree.set_pos(u"HOME")

    def set_filter(self):
        inf = self._window.show_modal_window(FiletreeFilterWindow(self.__filter_list))
        if inf[u'button'] == u'Cancel':
            return
        self.__filter_list = inf[u'st_list']
        self._window.settings.set(type(self).__name__, u'filter', self.__filter_list)
        self.__list_tree.set_file_filter(self.__filter_list)
        self.__filelist = self.__list_tree.get_filelist()
        self.__key_home()

    def set_active(self):
        if not self.visible or len(self.__filelist) == 0:
            return
        st = self.__filelist[self.__sel_pos][3]
        attr = self.__get_attr(st)
        if self.__filelist[self.__sel_pos][2] == False:
            str_tmp, tmp, attr_tmp = self.__line_and_attr[self.__sel_pos]
            self.__line_and_attr[self.__sel_pos] = (str_tmp, None,\
                    [(self.__x_pos, self.__x_pos + self.__width, \
                 curses.color_pair(curses.pair_number(attr)+1)|curses.A_REVERSE)])

        else:
            str_tmp, tmp, attr_tmp = self.__line_and_attr[self.__sel_pos]
            self.__line_and_attr[self.__sel_pos] = (str_tmp, None,\
                    [(self.__x_pos, self.__x_pos + self.__width, \
                    self._window.color_scheme.selected_inv | \
                            curses.A_REVERSE | curses.A_BOLD)])
        self.__upd()

    def set_inactive(self):
        if not self.visible or len(self.__filelist) == 0:
            return
        st = self.__filelist[self.__sel_pos][3]
        attr = self.__get_attr(st)
        #if self.__filelist[self.__sel_pos][2] == False:
        #    self.__pad.chgat(self.__sel_pos, self.__x_pos,
        #                    self.__x_pos + self.__width, attr)
        #else:
        #    self.__pad.chgat(self.__sel_pos, self.__x_pos,
        #                    self.__x_pos + self.__width, self.__attr1|curses.A_BOLD)

        # Всегда оставляем "лёгкое" выделение
        str_tmp, tmp, attr_tmp = self.__line_and_attr[self.__sel_pos]
        self.__line_and_attr[self.__sel_pos] = (str_tmp, None,\
                [(self.__x_pos, self.__x_pos + self.__width, \
                self._window.color_scheme.selected | curses.A_BOLD)])
        self.__upd()

    def set_files(self, files, content_only=False):
        """
        Функция сохраняет список файлов в дерево.

        Аргументы:
        files - список файлов (пути относительно корня) и их статусов.
        content_only -- не перерисовывать панель
        """

        self.__list_tree.set_files(files)
        self.__key_home()
        self.__list_tree.set_file_filter(self.__filter_list)
        self.__filelist = self.__list_tree.get_filelist()
        self.__upd_pad()
        if not content_only:
            self.__upd()

    def get_selected_files(self):
        """
        Функция возвращает список путей к выделенным файлам

        Возвращаемое значение:
        s_list - список файлов
        """

        return self.__list_tree.get_selected_files()

    def get_curpath(self, ignore_dirs=True):
        """
        Функция возвращает текущий путь
        ignore_dirs (по умолчанию - True) - если установлен в True, то для
        директорий возвращается пустая строка
        Возвращаемое значение:
        curpath - текущий путь
        """

        return self.__list_tree.get_curpath(ignore_dirs)
